<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vue API 接口测试工具</title>
  <style>
    body {
      font-family: 'Arial', sans-serif;
      max-width: 1200px;
      margin: 0 auto;
      padding: 20px;
      background-color: #f5f7fa;
    }
    .container {
      background-color: white;
      border-radius: 8px;
      box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
      padding: 20px;
    }
    h1 {
      color: #409eff;
      text-align: center;
      margin-bottom: 30px;
    }
    .api-group {
      margin-bottom: 20px;
      border: 1px solid #ebeef5;
      border-radius: 4px;
    }
    .group-title {
      background-color: #f5f7fa;
      padding: 10px 15px;
      margin: 0;
      font-size: 16px;
      font-weight: bold;
      border-bottom: 1px solid #ebeef5;
      cursor: pointer;
    }
    .api-list {
      padding: 10px 15px;
    }
    .api-item {
      margin-bottom: 10px;
      padding: 10px;
      border: 1px solid #ebeef5;
      border-radius: 4px;
    }
    .api-name {
      font-weight: bold;
      margin-bottom: 5px;
    }
    .method {
      display: inline-block;
      padding: 2px 6px;
      border-radius: 3px;
      color: white;
      font-size: 12px;
      margin-right: 8px;
    }
    .get {
      background-color: #67c23a;
    }
    .post {
      background-color: #409eff;
    }
    .put {
      background-color: #e6a23c;
    }
    .delete {
      background-color: #f56c6c;
    }
    .api-url {
      color: #606266;
      margin-bottom: 10px;
    }
    .api-actions {
      margin-top: 10px;
    }
    .test-btn {
      padding: 8px 15px;
      background-color: #409eff;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
    }
    .test-btn:hover {
      background-color: #66b1ff;
    }
    .result {
      margin-top: 10px;
      padding: 10px;
      background-color: #f8f8f8;
      border-radius: 4px;
      white-space: pre-wrap;
      overflow-x: auto;
      max-height: 200px;
      overflow-y: auto;
    }
    .success {
      color: #67c23a;
    }
    .error {
      color: #f56c6c;
    }
    .params-input {
      width: 100%;
      padding: 8px;
      box-sizing: border-box;
      margin-bottom: 10px;
      border: 1px solid #dcdfe6;
      border-radius: 4px;
    }
    .summary {
      margin-top: 20px;
      padding: 15px;
      background-color: #f5f7fa;
      border-radius: 4px;
    }
    .stats {
      display: flex;
      justify-content: space-around;
      margin-top: 10px;
    }
    .stat-item {
      text-align: center;
    }
    .stat-value {
      font-size: 24px;
      font-weight: bold;
    }
    .stat-label {
      font-size: 14px;
      color: #606266;
    }
    .progress-bar {
      height: 10px;
      background-color: #ebeef5;
      border-radius: 5px;
      margin-top: 10px;
      overflow: hidden;
    }
    .progress {
      height: 100%;
      background-color: #409eff;
      width: 0%;
      transition: width 0.3s;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>Vue API 接口测试工具</h1>
    
    <div class="api-config">
      <h3>基础设置</h3>
      <div>
        <label for="baseUrl">API基础URL:</label>
        <input type="text" id="baseUrl" class="params-input" value="http://127.0.0.1:5000/api">
      </div>
      <div style="margin-top: 10px;">
        <label for="authToken">认证Token (JWT):</label>
        <input type="text" id="authToken" class="params-input" placeholder="Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...">
      </div>
      <div style="margin-top: 10px;">
        <button id="testAllBtn" class="test-btn">测试所有接口</button>
        <button id="clearResultsBtn" class="test-btn" style="background-color: #909399;">清除所有结果</button>
      </div>
    </div>
    
    <div class="summary">
      <h3>测试统计</h3>
      <div class="stats">
        <div class="stat-item">
          <div class="stat-value" id="totalCount">0</div>
          <div class="stat-label">总接口数</div>
        </div>
        <div class="stat-item">
          <div class="stat-value success" id="successCount">0</div>
          <div class="stat-label">成功</div>
        </div>
        <div class="stat-item">
          <div class="stat-value error" id="failedCount">0</div>
          <div class="stat-label">失败</div>
        </div>
        <div class="stat-item">
          <div class="stat-value" id="pendingCount">0</div>
          <div class="stat-label">未测试</div>
        </div>
      </div>
      <div class="progress-bar">
        <div class="progress" id="progressBar"></div>
      </div>
    </div>
    
    <div id="apiGroups"></div>
  </div>

  <script>
    // API 接口定义
    const apiGroups = [
      {
        name: '配置管理 (系统配置)',
        apis: [
          { name: '获取公开配置', method: 'GET', url: '/configs/public', params: {} },
          { name: '获取配置by键名', method: 'GET', url: '/configs/get/site_name', params: {} },
          { name: '获取公开配置by键名', method: 'GET', url: '/configs/mp/get/site_name', params: {} },
          { name: '获取所有配置', method: 'GET', url: '/configs', params: {} }
        ]
      },
      {
        name: '配置管理 (应用配置)',
        apis: [
          { name: '获取配置列表', method: 'GET', url: '/admin/configs', params: { page: 1, per_page: 10 } },
          { name: '获取配置详情', method: 'GET', url: '/admin/configs/1', params: {} }
        ]
      },
      {
        name: '轮播图管理',
        apis: [
          { name: '获取轮播图列表', method: 'GET', url: '/banners', params: { page: 1, limit: 10 } },
          { name: '获取轮播图详情', method: 'GET', url: '/banners/1', params: {} }
        ]
      },
      {
        name: '文章管理',
        apis: [
          { name: '获取文章列表', method: 'GET', url: '/articles', params: { page: 1, limit: 10 } },
          { name: '获取文章详情', method: 'GET', url: '/articles/1', params: {} }
        ]
      },
      {
        name: '公告管理',
        apis: [
          { name: '获取公告列表', method: 'GET', url: '/notices', params: { page: 1, limit: 10 } },
          { name: '获取公告详情', method: 'GET', url: '/notices/1', params: {} }
        ]
      },
      {
        name: '用户管理',
        apis: [
          { name: '获取用户列表', method: 'GET', url: '/users', params: { page: 1, per_page: 20 } }
        ]
      },
      {
        name: '代理管理',
        apis: [
          { name: '获取代理列表', method: 'GET', url: '/agents', params: { page: 1, per_page: 10 } },
          { name: '获取代理树状结构', method: 'GET', url: '/agents/tree', params: {} }
        ]
      },
      {
        name: '订单管理',
        apis: [
          { name: '获取订单列表', method: 'GET', url: '/orders', params: { page: 1, limit: 10 } },
          { name: '获取订单统计', method: 'GET', url: '/orders/statistics', params: {} }
        ]
      },
      {
        name: '反馈管理',
        apis: [
          { name: '获取反馈列表', method: 'GET', url: '/feedbacks', params: { page: 1, limit: 10 } }
        ]
      },
      {
        name: '套餐管理',
        apis: [
          { name: '获取套餐列表', method: 'GET', url: '/plans', params: { page: 1, limit: 10 } },
          { name: '获取套餐详情', method: 'GET', url: '/plans/1', params: {} }
        ]
      }
    ];

    // 渲染API组和接口
    function renderApiGroups() {
      const container = document.getElementById('apiGroups');
      let totalCount = 0;
      
      apiGroups.forEach((group, groupIndex) => {
        const groupDiv = document.createElement('div');
        groupDiv.className = 'api-group';
        
        const groupTitle = document.createElement('h3');
        groupTitle.className = 'group-title';
        groupTitle.textContent = group.name;
        groupTitle.onclick = () => {
          const apiList = document.getElementById(`apiList-${groupIndex}`);
          apiList.style.display = apiList.style.display === 'none' ? 'block' : 'none';
        };
        
        const apiList = document.createElement('div');
        apiList.className = 'api-list';
        apiList.id = `apiList-${groupIndex}`;
        
        group.apis.forEach((api, apiIndex) => {
          totalCount++;
          const apiItem = document.createElement('div');
          apiItem.className = 'api-item';
          apiItem.id = `api-${groupIndex}-${apiIndex}`;
          
          const apiName = document.createElement('div');
          apiName.className = 'api-name';
          
          const methodSpan = document.createElement('span');
          methodSpan.className = `method ${api.method.toLowerCase()}`;
          methodSpan.textContent = api.method;
          
          apiName.appendChild(methodSpan);
          apiName.appendChild(document.createTextNode(api.name));
          
          const apiUrl = document.createElement('div');
          apiUrl.className = 'api-url';
          apiUrl.textContent = api.url;
          
          const paramsInput = document.createElement('input');
          paramsInput.type = 'text';
          paramsInput.className = 'params-input';
          paramsInput.value = JSON.stringify(api.params);
          paramsInput.id = `params-${groupIndex}-${apiIndex}`;
          
          const apiActions = document.createElement('div');
          apiActions.className = 'api-actions';
          
          const testBtn = document.createElement('button');
          testBtn.className = 'test-btn';
          testBtn.textContent = '测试接口';
          testBtn.onclick = () => testApi(groupIndex, apiIndex);
          
          const resultDiv = document.createElement('div');
          resultDiv.className = 'result';
          resultDiv.id = `result-${groupIndex}-${apiIndex}`;
          resultDiv.style.display = 'none';
          
          apiActions.appendChild(testBtn);
          
          apiItem.appendChild(apiName);
          apiItem.appendChild(apiUrl);
          apiItem.appendChild(paramsInput);
          apiItem.appendChild(apiActions);
          apiItem.appendChild(resultDiv);
          
          apiList.appendChild(apiItem);
        });
        
        groupDiv.appendChild(groupTitle);
        groupDiv.appendChild(apiList);
        container.appendChild(groupDiv);
      });
      
      document.getElementById('totalCount').textContent = totalCount;
      document.getElementById('pendingCount').textContent = totalCount;
    }

    // 测试单个API
    async function testApi(groupIndex, apiIndex) {
      const api = apiGroups[groupIndex].apis[apiIndex];
      const resultDiv = document.getElementById(`result-${groupIndex}-${apiIndex}`);
      const paramsInput = document.getElementById(`params-${groupIndex}-${apiIndex}`);
      
      resultDiv.style.display = 'block';
      resultDiv.textContent = '测试中...';
      resultDiv.className = 'result';
      
      const baseUrl = document.getElementById('baseUrl').value;
      const authToken = document.getElementById('authToken').value;
      
      try {
        const params = JSON.parse(paramsInput.value);
        let url = baseUrl + api.url;
        
        // 处理GET请求的查询参数
        if (api.method === 'GET' && Object.keys(params).length > 0) {
          const queryParams = new URLSearchParams();
          for (const key in params) {
            queryParams.append(key, params[key]);
          }
          url += `?${queryParams.toString()}`;
        }
        
        const options = {
          method: api.method,
          headers: {
            'Content-Type': 'application/json'
          }
        };
        
        if (authToken) {
          options.headers['Authorization'] = authToken;
        }
        
        if (api.method !== 'GET' && Object.keys(params).length > 0) {
          options.body = JSON.stringify(params);
        }
        
        const response = await fetch(url, options);
        const data = await response.json();
        
        resultDiv.textContent = JSON.stringify(data, null, 2);
        
        if (response.ok) {
          resultDiv.classList.add('success');
          updateStats(true);
        } else {
          resultDiv.classList.add('error');
          updateStats(false);
        }
      } catch (error) {
        resultDiv.textContent = `错误: ${error.message}`;
        resultDiv.classList.add('error');
        updateStats(false);
      }
    }

    // 测试所有API
    async function testAllApis() {
      let successCount = 0;
      let failedCount = 0;
      let totalCount = 0;
      
      // 重置统计
      document.getElementById('successCount').textContent = '0';
      document.getElementById('failedCount').textContent = '0';
      document.getElementById('pendingCount').textContent = apiGroups.reduce((sum, group) => sum + group.apis.length, 0);
      document.getElementById('progressBar').style.width = '0%';
      
      for (let groupIndex = 0; groupIndex < apiGroups.length; groupIndex++) {
        const group = apiGroups[groupIndex];
        for (let apiIndex = 0; apiIndex < group.apis.length; apiIndex++) {
          const api = group.apis[apiIndex];
          const resultDiv = document.getElementById(`result-${groupIndex}-${apiIndex}`);
          const paramsInput = document.getElementById(`params-${groupIndex}-${apiIndex}`);
          
          resultDiv.style.display = 'block';
          resultDiv.textContent = '测试中...';
          resultDiv.className = 'result';
          
          const baseUrl = document.getElementById('baseUrl').value;
          const authToken = document.getElementById('authToken').value;
          
          try {
            const params = JSON.parse(paramsInput.value);
            let url = baseUrl + api.url;
            
            // 处理GET请求的查询参数
            if (api.method === 'GET' && Object.keys(params).length > 0) {
              const queryParams = new URLSearchParams();
              for (const key in params) {
                queryParams.append(key, params[key]);
              }
              url += `?${queryParams.toString()}`;
            }
            
            const options = {
              method: api.method,
              headers: {
                'Content-Type': 'application/json'
              }
            };
            
            if (authToken) {
              options.headers['Authorization'] = authToken;
            }
            
            if (api.method !== 'GET' && Object.keys(params).length > 0) {
              options.body = JSON.stringify(params);
            }
            
            const response = await fetch(url, options);
            const data = await response.json();
            
            resultDiv.textContent = JSON.stringify(data, null, 2);
            
            if (response.ok) {
              resultDiv.classList.add('success');
              successCount++;
            } else {
              resultDiv.classList.add('error');
              failedCount++;
            }
          } catch (error) {
            resultDiv.textContent = `错误: ${error.message}`;
            resultDiv.classList.add('error');
            failedCount++;
          }
          
          totalCount++;
          
          // 更新进度
          document.getElementById('successCount').textContent = successCount;
          document.getElementById('failedCount').textContent = failedCount;
          document.getElementById('pendingCount').textContent = document.getElementById('totalCount').textContent - successCount - failedCount;
          document.getElementById('progressBar').style.width = `${(totalCount / apiGroups.reduce((sum, group) => sum + group.apis.length, 0)) * 100}%`;
          
          // 给UI渲染的时间
          await new Promise(resolve => setTimeout(resolve, 100));
        }
      }
    }

    // 更新统计数据
    function updateStats(success) {
      const successCount = parseInt(document.getElementById('successCount').textContent);
      const failedCount = parseInt(document.getElementById('failedCount').textContent);
      const totalCount = parseInt(document.getElementById('totalCount').textContent);
      
      if (success) {
        document.getElementById('successCount').textContent = successCount + 1;
      } else {
        document.getElementById('failedCount').textContent = failedCount + 1;
      }
      
      document.getElementById('pendingCount').textContent = totalCount - (successCount + failedCount + 1);
      
      const testedCount = successCount + failedCount + 1;
      document.getElementById('progressBar').style.width = `${(testedCount / totalCount) * 100}%`;
    }

    // 清除所有结果
    function clearAllResults() {
      apiGroups.forEach((group, groupIndex) => {
        group.apis.forEach((api, apiIndex) => {
          const resultDiv = document.getElementById(`result-${groupIndex}-${apiIndex}`);
          resultDiv.style.display = 'none';
          resultDiv.textContent = '';
          resultDiv.className = 'result';
        });
      });
      
      // 重置统计
      document.getElementById('successCount').textContent = '0';
      document.getElementById('failedCount').textContent = '0';
      document.getElementById('pendingCount').textContent = document.getElementById('totalCount').textContent;
      document.getElementById('progressBar').style.width = '0%';
    }

    // 初始化页面
    document.addEventListener('DOMContentLoaded', () => {
      renderApiGroups();
      
      document.getElementById('testAllBtn').addEventListener('click', testAllApis);
      document.getElementById('clearResultsBtn').addEventListener('click', clearAllResults);
    });
  </script>
</body>
</html> 